#!/usr/bin/env python
# USP Reminder Plugin Version 1.0
##Description:Reminders only (no calendar)
import gtk
import gtk.glade
import sys
import os
import pango
import gobject
import datetime
import gconf
from execute import Execute
from easygconf import SetGconf
from easygconf import WriteGconf

class pluginclass:
	TARGET_TYPE_TEXT = 80
	toButton = [ ( "text/uri-list", 0, TARGET_TYPE_TEXT ) ]
	"""This is the main class for the plugin"""
	"""It MUST be named pluginclass"""

	def __init__(self, USPWin):
		self.USPWin = USPWin

		#The Glade file for the plugin
		self.gladefile = os.path.join(os.path.dirname(__file__), "remind.glade")

		#Read GLADE file
		self.wTree = gtk.glade.XML(self.gladefile,"window1")

		#These properties are NECESSARY to maintain consistency
		#throughout USP

		#Set 'window' property for the plugin (Must be the root widget)
		self.window = self.wTree.get_widget("window1")

		#Set 'heading' property for plugin
		self.heading = "Reminders"

		#This should be the first item added to the window in glade
		self.content_holder = self.wTree.get_widget("eventbox1")
		self.tasks=self.wTree.get_widget("TaskView")
		self.apps=self.wTree.get_widget("AppointView")

		#Specify plugin width

		#Plugin icon
		self.icon = 'gnome-calendar.png'

		self.gconf_dir = '/apps/usp/plugins/calendar'
		self.client = gconf.client_get_default()
		self.client.add_dir('/apps/usp/plugins/calendar', gconf.CLIENT_PRELOAD_NONE)
		self.client.notify_add('/apps/usp/plugins/calendar/sticky',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/icon',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/height',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/height_appoints',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/height_tasks',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/width',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/item_font_size',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calendar/heading_font_size',self.RegenPlugin)

		self.datetoday=datetime.datetime.today()
		#self.datetoday='20061009' """Test Date String for Debug/Testing"""

		#Connect event handlers
		dic = {"on_window1_destroy" : gtk.main_quit}
		self.wTree.signal_autoconnect(dic)
	
		self.GetGconfEntries()
		#Setup Viewers
		self.tstore=gtk.ListStore(str)
		self.tasks.set_model(self.tstore)
		self.trender = gtk.CellRendererText()
		self.trender.set_property('size',self.itemsize*1000)
		self.tcolumn = gtk.TreeViewColumn("Task",self.trender,text=0) 
		self.tasks.append_column(self.tcolumn)
		self.astore=gtk.ListStore(str)
		self.apps.set_model(self.astore)
		self.arender = gtk.CellRendererText()
		self.arender.set_property('size',self.itemsize*1000)
		self.acolumn = gtk.TreeViewColumn("Task",self.arender,text=0) 
		self.apps.append_column(self.acolumn)
		self.RegenPlugin()
		#items=["eventbox1","MainScrolledWindow","viewport1","vbox1","TaskLabel","AppointLabel"]
		#i=0	
		#while i < len(items):
		#	self.wTree.get_widget(items[i]).modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.customcolor))
		#	i+=1
		#gobject.timeout_add(1000, self.DoTasks)
		return

	def RegenPlugin(self, *args, **kargs):
		self.GetGconfEntries()
		self.DoTasks()
		#gobject.timeout_add(1000, self.DoTasks)

	def GetGconfEntries(self):
		self.client = gconf.client_get_default()
		self.sticky = SetGconf( self.client, "bool", "/apps/usp/plugins/calendar/sticky", False )
		self.minimized = SetGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", False )
		self.icon = SetGconf( self.client, "string", "/apps/usp/plugins/calendar/icon", "gnome-calendar.png" )
		self.headingsize = SetGconf(self.client,'int','/apps/usp/plugins/calendar/heading_font_size',9)
		self.itemsize = SetGconf(self.client,'int','/apps/usp/plugins/calendar/item_font_size',8)
		self.h_apps = SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_appoints', 60)
		self.h_tasks = SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_tasks', 60)
		self.height = SetGconf(self.client,'int','/apps/usp/plugins/calendar/height', 100)
		self.width= SetGconf(self.client,'int','/apps/usp/plugins/calendar/width', 200)

	def SetHidden( self, state ):
		if state == True:
			WriteGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", True )
		else:
			WriteGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", False )

	def DoTasks(self):
		HStyle = pango.AttrList()
		attr = pango.AttrSize(self.headingsize*1000,0,-1)
		HStyle.insert(attr)
		LStyle = pango.AttrList()
		attr = pango.AttrSize(self.itemsize*1000,0,-1)
		LStyle.insert(attr)
		os.chdir(os.path.expanduser("~"))
		# Get Tasks File IN
		try:
			in_file=open(os.path.expanduser("~")+'/.evolution/tasks/local/system/tasks.ics','r')
			self.task_file=in_file.read()
			in_file.close()
		except:
			self.task_file=""
		# Get Appointments File IN
		#folder = os.path.expanduser("~")+'/.usp/plugins/'
		folder = os.path.expanduser("~")+'/.evolution/calendar/local/system/'
		pattern = "calendar.ics"
		filename = os.path.join(folder, pattern)
		self.app_file=[]
		try:
			in_file=open( filename, 'r' )
			temp_in=in_file.readlines()
			in_file.close()
			self.app_file=temp_in
		except:
			self.app_file=[]
		# "Begin Parsing Tasks File....."
		taskview=[]
		start=self.task_file.find("BEGIN:VTODO")
		while start != -1:
			self.task_file=self.task_file[start:]
			self.task_file=self.task_file[self.task_file.find("SUMMARY:")+len("SUMMARY:"):]
			end=self.task_file.find("\n")
			sectionend=self.task_file.find("END:VTODO")
			if self.task_file[:sectionend].find("STATUS:COMPLETED")==-1:
				taskview.append(self.task_file[:end])
			start=self.task_file.find("BEGIN:VTODO")
		# ".........End Parsing Tasks File."
		self.tstore.clear()
		# Add Tasks to List
		for reminds in taskview:
			self.tstore.append([reminds])
		# "Begin Parsing Appointments File....."
		TotalAppoints = []
		appsview = []
		appdate = Summary = ""
		numlines = len(self.app_file)
		InEvent = False
		FreqArray = []
		line = Interval = Numdays = Count = ByDayofMonth = 0
		DayArray=["MO","TU","WE","TH","FR","SA","SU"]
		while line < numlines:
			Errored=False
			Test = self.app_file[line].strip( "\n" )
			if Test.find( "BEGIN:VEVENT" ) != -1:
				FreqArray = []
				ExcludeArray = []
				Interval = Numdays = Count = ByDayofMonth = 0
				appsview = []
				InEvent = True
			if Test.find( "DTSTART;" ) != -1 and InEvent == True:
				# Have to check next line as Evolution randomly splits the line over two.
				NextLine = self.app_file[line+1]
				if NextLine.find( "TZID" ) != -1:
					Temp = NextLine.strip( "\n" ).strip( " " ).split(":")
					Test = Temp[1][0:8]
					appdate = Test[Test.find(":")+1:]
				elif Test.split(":")[1] == "":
					appdate = NextLine.strip()[0:8]
				else:
					appdate = Test.split(':')[1]
				appdateformat = self.datetoday.date
				try:
					appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8]))
					appsview.append(appdateformat)
				except:
					line += 1
					InEvent = False
				if InEvent == True:
					EndLine=self.app_file[line+2]
					# Check old Nextline first
					if NextLine.find( "DTEND;" ) != -1:
						# Have to check next line as Evolution randomly splits the line over two.
						NextLine_2 = self.app_file[line+2]
						if NextLine.find( "TZID" ) != -1:
							Temp = NextLine.strip( "\n" ).strip( " " ).split(":")
							Test = Temp[1][0:8]
							appdate = Test[Test.find(":")+1:]
						elif Test.split(":")[1] == "":
							appdate = NextLine.strip()[0:8]
						else:
							appdate = Test.split(':')[1]
						appdateformat = self.datetoday.date
						try:
							appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8]))
							appsview.append(appdateformat)
						except:
							appsview.append("")
							pass
					elif EndLine.find( "DTEND;" ) != -1:
						#print EndLine
						# Have to check next line as Evolution randomly splits the line over two.
						NextLine_2 = self.app_file[line+3]
						if NextLine_2.find( "TZID" ) != -1:
							Temp = NextLine_2.strip( "\n" ).strip( " " ).split(":")
							Test = Temp[1][0:8]
							appdate = Test[Test.find(":")+1:]
						elif Test.split(":")[1] == "":
							appdate = NextLine_2.strip()[0:8]
						else:
							appdate = EndLine.split(':')[1]
						appdateformat = self.datetoday.date
						#print NextLine_2
						try:
							appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8]))
							appsview.append(appdateformat)
						except:
							appsview.append("")
							pass
					else:
						appsview.append("")
			if InEvent == True:
				if Test.find( "EXDATE" ) != -1:
					exdate=Test.split(":")[1][0:8]
					try:
						Temp=datetime.date(int(exdate[0:4]),int(exdate[4:6]),int(exdate[6:8]))
						ExcludeArray.append(Temp)
					except:
						pass
				if Test.find( "RRULE" ) != -1:
					try:
						# Have to check next line as Evolution randomly splits the line over two.
						NextLine = self.app_file[line+1]
						if NextLine.find( "INTERVAL" ) != -1 or NextLine.find( "BYDAY" ) != -1 or NextLine.find( "BYMONTHDAY" ) != -1:
							Test = Test.strip( "\n" ) + NextLine.strip( "\n" ).strip( " " )
					except:
						pass
					FreqArray=Test.split(":")
					FreqArray = FreqArray[1].split( ";" )
					AddValuetoDays = False
					AddValuetoWeeks = False
					AddValuetoMonths = False
					AddValuetoYears = False
					if FreqArray[0] == 'FREQ=DAILY':
						AddValuetoDays = True
						Interval = int( FreqArray[2][9:].split( "\n" )[0] )
					if FreqArray[0] == 'FREQ=WEEKLY':
						AddValuetoWeeks = True
						Interval = int( FreqArray[2][9:].split( "\n" )[0] )*7
					if FreqArray[0] == 'FREQ=MONTHLY':
						AddValuetoMonths = True
						Interval = int( FreqArray[2][9:].split( "\n" )[0] )
						try:
							ByDayofMonth = int( FreqArray[3][11:].split("\n")[0] )
						except:
							ByDayofMonth = 0
							pass
					if FreqArray[0] == 'FREQ=YEARLY':
						AddValuetoYears = True
					Count = int( FreqArray[1][6:].split("\n")[0] )
				if Test.find( "SUMMARY:" ) != -1:
					SumStart = Test.find( "SUMMARY:" )+len( "SUMMARY:" )
					SumStop = Test.find( "\n", SumStart )
					Summary = Test[SumStart:]
					appsview.append(Summary)
				if Test.find( "END:VEVENT" ) != -1:
					appsview.append(FreqArray)
					appsview.append(ExcludeArray)
					TotalAppoints.append( appsview )
					InEvent = False
			line += 1
		clicked_date=self.datetoday.date
		if self.USPWin.VERBOSE == True:
			print "\nTotalAppoints Array\n-------------------"
		DisplayAppoints = []
		# Now work out Repeated Appointments
		for appoints in TotalAppoints:
			if self.USPWin.VERBOSE == True:
				print appoints
			if len( appoints[3] ) > 0:
				if appoints[3][0] == "FREQ=DAILY":
					Count = int( appoints[3][1][6:] )
					Interval = int( appoints[3][2][9:] )
					Ctr = 0
					DisplayAppoints.append( [appdate, appoints[2]] )
					while Ctr <= Count:
						advance=(Interval*Ctr)
						appdate=appoints[0]+datetime.timedelta( days = advance )
						# Check if it's Excluded
						Excluded = False
						if len( appoints[4] ) > 0:
							try:
								appoints[4].index( appdate )
								Excluded = True
							except:
								pass
						if Excluded == False:
							DisplayAppoints.append( [appdate, appoints[2]] )
						Ctr+=1
				if appoints[3][0] == "FREQ=WEEKLY":
					Count = int( appoints[3][1][6:] )
					Interval = int( appoints[3][2][9:] ) * 7
					ByDayofWeek = -1
					if len( appoints[3] ) == 4:
						try:
							ByDayofWeek = DayArray.index( appoints[2][3][6:] )
						except:
							pass
					Ctr = 0
					DisplayAppoints.append( [appoints[0], appoints[2]] )
					while Ctr < Count:
						if ByDayofWeek != -1:
							advance=(Interval*Ctr) + (ByDayofWeek+1)
						else:
							advance=(Interval*Ctr)
						appdate=appoints[0]+datetime.timedelta( days = advance )
						# Check if it's Excluded
						Excluded = False
						if len( appoints[4] ) > 0:
							try:
								appoints[4].index( appdate )
								Excluded = True
							except:
								pass
						if Excluded == False:
							DisplayAppoints.append( [appdate, appoints[2]] )
						Ctr+=1
				if appoints[3][0] == "FREQ=MONTHLY":
					Count = int( appoints[3][1][6:] )
					Interval = int( appoints[3][2][9:] )
					ByDayofMonth = -1
					if len( appoints[3] ) == 4:
						try:
							ByDayofMonth = int( appoints[3][3][11:] )
						except:
							pass
					Ctr = 0
					DisplayAppoints.append( [appoints[0], appoints[2]] )
					while Ctr < Count:
						appdate=self.addMonth( appoints[0], Interval*Ctr )
						if ByDayofMonth != -1:
							appdate=appdate.replace(day=ByDayofMonth)
						# Check if it's Excluded
						Excluded = False
						if len( appoints[4] ) > 0:
							try:
								appoints[4].index( appdate )
								Excluded = True
							except:
								pass
						if Excluded == False and appdate >= appoints[0]:
							DisplayAppoints.append( [appdate, appoints[2]] )
						Ctr+=1
				if appoints[3][0] == "FREQ=YEARLY":
					Count = int( appoints[3][1][6:] )
					Interval = int( appoints[3][2][9:] )
					Ctr = 1
					DisplayAppoints.append( [appoints[0], appoints[2]] )
					while Ctr < Count:
						appsyear = appoints[0].year + ( Interval*Ctr )
						appdate = appoints[0].replace(year=appsyear)
						# Check if it's Excluded
						Excluded = False
						if len( appoints[4] ) > 0:
							try:
								appoints[4].index( appdate )
								Excluded = True
							except:
								pass
						if Excluded == False and appdate >= appoints[0]:
							DisplayAppoints.append( [appdate, appoints[2]] )
						Ctr+=1
			else:
				done = False
				PostDate = appoints[0]
				Ctr = 1
				while PostDate <= appoints[1]:
					DisplayAppoints.append( [PostDate, appoints[2]] )
					PostDate = appoints[0]+datetime.timedelta( days = Ctr )
					Ctr+=1
					

		self.astore.clear()
		if self.USPWin.VERBOSE == True:
			print "\nDisplayAppoints Array\n---------------------"
		# Add Appointments to List
		for appoints in DisplayAppoints:
			if self.USPWin.VERBOSE == True:
				print appoints
			# FOR SOME REASON MONTH IS ZERO OFFSET SO NEED TO ADD ONE TO MONTH ??????
			#self.datetoday=datetime.datetime( clicked_date[0], clicked_date[1]+1, clicked_date[2] )
			if appoints[0].year == self.datetoday.year and appoints[0].month == self.datetoday.month and appoints[0].day == self.datetoday.day:
				self.astore.append( [appoints[1]] )
		# ".........End Parsing Appointments File."
		try:
			self.wTree.get_widget("CalRemViewPort").set_size_request(self.width,self.height)
			self.wTree.get_widget("scrolledwindow1").set_size_request(self.width,self.h_tasks)
			self.wTree.get_widget("scrolledwindow2").set_size_request(self.width,self.h_apps)
		except:
			pass
		self.wTree.get_widget("TaskLabel").set_attributes(HStyle)
		self.wTree.get_widget("AppointLabel").set_attributes(HStyle)
		return True

	def addMonth(self, date, n=1):
		OneDay = datetime.timedelta(days=1)
		# add n+1 months to date then subtract 1 day
		# to get eom, last day of target month
		q,r = divmod(date.month+n, 12)
		eom = datetime.date(date.year+q, r+1, 1) - OneDay
		if date.month != (date+OneDay).month or date.day >= eom.day:
			return eom
		return eom.replace(day=date.day)

#---------------------------------------------------------------------------------------#
# USPconfig Section Below
#---------------------------------------------------------------------------------------#
# This is the Config Class it must be called "cfgpluginclass' and the gtk.Window must be called 'config'
class cfgpluginclass:
	def __init__(self):
		# The Gladefile for the plugins USPconfig Tab
		self.gladefile = os.path.join(os.path.dirname(__file__), "remind.glade")
		# Read GLADE file
		self.wTree = gtk.glade.XML(self.gladefile,"config")
		# Set 'window' property for the plugin (Must be the root widget)
		self.window = self.wTree.get_widget("config")
		# Content Place Holder must be eventbox2
		self.content_holder = self.wTree.get_widget("eventbox2")
		# Set Heading, this will be used for the tab label in USPconfig
		self.heading = "Reminders"
		# GConf Stuff - This just makes sure a gconf path is there.
		self.gconf_dir = '/apps/usp/plugins/calendar'
		self.client = gconf.client_get_default()
		self.client.add_dir('/apps/usp/plugins/calendar', gconf.CLIENT_PRELOAD_NONE)
		# Setup the Functions of the Glade files spin controls or entry boxes for Value Changes
		# Tip: For spinbutton controls use the "_value_changed" event not the "_changed" event.
		dic = { "on_window2_destroy" : gtk.main_quit,
				"on_CalHSpin_changed" : self.height_spin,
				"on_CalWSpin_changed" : self.width_spin,
				"on_CalTasksHSpin_changed" : self.tasks_h_spin,
				"on_CalAppsHSpin_changed" : self.apps_h_spin,
				"on_CalHeadSizeSpin_changed" : self.head_spin,
				"on_CalItemSizeSpin_changed" : self.item_spin,
				"on_CalIconEntry_changed" : self.icon_changed,
				"on_CalShowChkBtn_toggled" : self.show_t_a,
				"on_StickyChkBtn_toggled" : self.sticky}
		self.wTree.signal_autoconnect(dic)
		# Read Values from GConf for USPconfig Tab and Set Default Values in GConf if they don't exist.
		self.wTree.get_widget("StickyChkBtn").set_active(SetGconf(self.client,'bool','/apps/usp/plugins/calendar/sticky',False))
		self.wTree.get_widget("CalIconEntry").set_text(SetGconf( self.client, "string", '/apps/usp/plugins/calendar/icon', "gnome-calendar.png"))
		self.wTree.get_widget("CalHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height',200))
		self.wTree.get_widget("CalWSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/width',250))
		self.wTree.get_widget("CalTasksHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_tasks',80))
		self.wTree.get_widget("CalAppsHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_appoints',80))
		self.wTree.get_widget("CalHeadSizeSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/heading_font_size',10))
		self.wTree.get_widget("CalItemSizeSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/item_font_size',8))
		self.wTree.get_widget("CalShowChkBtn").set_active(SetGconf(self.client,'bool','/apps/usp/plugins/calendar/show_tasks_appoints',False))

	# Functions for Changing Values when items checked or altered.
	def sticky(self, *args, **kargs):
		if self.wTree.get_widget("StickyChkBtn").get_active() == True:
			self.client.set_bool('/apps/usp/plugins/calendar/sticky',True)
		else:
			self.client.set_bool('/apps/usp/plugins/calendar/sticky',False)

	def icon_changed(self, *args, **kargs):
		self.client.set_string('/apps/usp/plugins/calendar/icon',self.wTree.get_widget("CalIconEntry").get_text())

	def height_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/height',int(self.wTree.get_widget("CalHSpin").get_value()))

	def width_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/width',int(self.wTree.get_widget("CalWSpin").get_value()))

	def tasks_h_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/height_tasks',int(self.wTree.get_widget("CalTasksHSpin").get_value()))

	def apps_h_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/height_appoints',int(self.wTree.get_widget("CalAppsHSpin").get_value()))

	def head_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/heading_font_size',int(self.wTree.get_widget("CalHeadSizeSpin").get_value()))

	def item_spin(self, *args, **kargs):
		self.client.set_int('/apps/usp/plugins/calendar/item_font_size',int(self.wTree.get_widget("CalItemSizeSpin").get_value()))

	def show_t_a(self, *args, **kargs):
		if self.wTree.get_widget("CalShowChkBtn").get_active() == True:
			self.client.set_bool('/apps/usp/plugins/calendar/show_tasks_appoints',True)
		else:
			self.client.set_bool('/apps/usp/plugins/calendar/show_tasks_appoints',False)
